<template>
  <div class="three-container">
    <!-- Three.js渲染容器 -->
    <div ref="renderContainer" class="render-container">
    </div>
    <div 
      ref="selectionBox" 
      class="selection-box"
      :style="{
        left: boxState.boxLeft + 'px',
        top: boxState.boxTop + 'px',
        width: boxState.boxWidth + 'px',
        height: boxState.boxHeight + 'px',
        display: boxState.isSelecting ? 'block' : 'none'
      }"
    ></div> 
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted, watchEffect } from 'vue';
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { Lut } from 'three/examples/jsm/math/Lut.js'; // 引入Lut模块
import * as CM from '@/utils/three/control_module.js';//threejs网格可控制模块
import * as DM from '@/utils/three/draw_module.js';//threejs网格绘制模块
import eventBus from '@/utils/eventBus.ts'
import { meshCreate } from '@/api/PyFem.js'
import { getOcct } from '@/utils/occt.ts'

// 容器引用
const renderContainer = ref(null);
// 状态管理
const meshsize = ref(5.0);
const geoObj = ref('');
//buffergeometry自定义几何模型对象
let Attributedict={}; //用于保存几何模型数据的对象
let iniPos,dispPos,deformRatio=ref(10.0),activeDeformRatio=0.0;//初始位置，位移变形量，变形比例
let group = new THREE.Group();//几何模型总组
let oriGeometryGroup = new THREE.Group();//几何模型总组
let wireframeGroup = new THREE.Group();//线框组对象,当前的方案是由前端获取线框，之后改由后端获取并发往前端
// 定义方盒参数，用于锁定模型几何大小
let BoxPara={'boundingBox':NaN, 'boxsize':NaN,'boxcenter':NaN};
//涉及到文件输入
let mshfile = '';
let resfile = '';
//---------三维模型上的点选相关变量--
let raycaster = new THREE.Raycaster(); // 创建射线投射器
let mouse = new THREE.Vector2(); // 创建一个二维向量用于存储标准设备坐标
let canvas; //画布，用于鼠标点击操作
let INTERSECTED;//用于临时保存相交几何对象
//-----------------
// ---框选状态（响应式）-----
const selectionBox = ref(null);
const boxState = reactive({
  isSelecting: false,
  startX: 0,
  startY: 0,
  boxLeft: 0,
  boxTop: 0,
  boxWidth: 0,
  boxHeight: 0,
  selectedObjs: [] // 选中点的索引
});
let selectedObjType,selectedObj;//selectedObjType表示需要选择的几何类型，selectedObj表示需要在总组中进行选择的几何对象，因为总组中几何对象只有点线面，对于体素网格，需要在面网格组中进行另外筛选。
const selectedObjFunc={
  'Points':selectPointsInRect,
  'LineSegments':selectLinesInRect,
  'Mesh':selectFacesInRect,
};
const resetSelectedObjFunc={
  'Points':resetPointsSelection,
  'LineSegments':resetLinesSelection,
  'Mesh':resetFacesSelection,
};
let originalColorObj;
const selectedColor = 0xff0000;
//----------------模型对象选择参数-------------------
//----------------剖面平面定义-------------------
let clippingPlane=null;
const clippingPlaneTag={
  'XY':2,
  'YZ':0,
  'ZX':1,
};
const clippingPlaneVectorRef={
  'XY':new THREE.Vector3( 0, 0, - 1 ),
  'YZ':new THREE.Vector3( - 1, 0, 0 ),
  'ZX':new THREE.Vector3( 0, - 1, 0 ),
};
//----------------剖面平面定义-------------------
// 引用文件选择器元素
const fileInput = ref(null);
// 错误信息
const errorMessage = ref('');
//------坐标系统定义------
let coordinateSystem,coordinateConfig,coordScene,coordCamera;
let coorWidth,coorHeight;
//-----------------
//独立2D颜色条场景
let colorBar,colorBarScene,colorBarCamera,lut,colorbarConfig;
// let colorbarSystem;
//----------------动画定义参数段-------------------
let morphFlag=false,morphAnimationFlag=false;
let frameCount;
let lastFrameCount = 0;
const totalframes = 15;//总帧数
const frameDuration = 1.0/totalframes; // 总帧数对应的单帧时长（秒）
let clock = new THREE.Clock();
let totalTime = 0;
const maxDuration = 10; // 最大10秒
//----------------动画定义参数段-------------------
// Three.js核心对象
let scene, camera, renderer, controls,backgroundColor;
let animationId = null;
// 初始化Three.js场景
const initScene = () => {
  // 创建场景
  backgroundColor=0xffffff;
  scene = new THREE.Scene();
  // scene.background = new THREE.Color(0x1a1a2e);
  scene.background = new THREE.Color(backgroundColor);
  // scene.background = null;


  // 创建相机
  camera = new THREE.PerspectiveCamera(
    75, 
    renderContainer.value.clientWidth / renderContainer.value.clientHeight, 
    0.1, 
    1000
  );
  camera.position.z = 10;

  // 创建渲染器
  renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.setSize(
    renderContainer.value.clientWidth, 
    renderContainer.value.clientHeight
  );
  renderContainer.value.appendChild(renderer.domElement);

  // 添加轨道控制器
  controls = new OrbitControls(camera, renderer.domElement);
  controls.enableDamping = true;
  controls.dampingFactor = 0.05;
  controls.addEventListener( 'change', renderScene );

  // 画布与渲染器关联
  canvas = renderer.domElement;
  // createCube();
  //加载网格文件
  scene.add(group);
  //----------------
  // meshload(mshfile,group);
  // resIni(resfile);
  // coordinateSystem = initCoordinateSystem();
  // colorbarSystem = initColorBar();
  initCoordinateSystem();
  initColorBar();
  // 监听窗口大小变化
  // canvas.addEventListener("click", onMouseClick);
  window.addEventListener('resize', handleResize);
  renderScene();
  //----------------
};

// ------------------------
async function meshload(mshfile,group){//加载网格文件，形成组，
     //
    var mshjsondata=await loadJSON(mshfile);
    Attributedict=CM.mshAttributesProc(mshjsondata);//根据导入的网格数据对象，形成本次要渲染mesh的数据对象体Attributedict
    iniPos=Attributedict['pointsarray'];//初始化初始位置
    dispPos = new Array(iniPos.length).fill(0);//初始化位移量为0
    DM.Oridata2groupmesh(Attributedict,group);//根据数据对象体Attributedict绘制渲染mesh，并形成group
    CM.BoxParaCreate(Attributedict.pointsarray,BoxPara);
    CM.camerazoommid(camera,BoxPara);
    // wireframeCreate();
    // wireframe.group.visible = false;
}
// ------------------------
async function resIni(resfile){//加载结果文件，形成组，
     //
    var jsondata=await loadJSON(resfile);
    var resFieldInfo=jsondata.results.availableFields
    // console.log(resFieldInfo);
    for (let i = 0; i < resFieldInfo.length; i++) {
        if (resFieldInfo[i].internalName=='Displacement'){//根据位移场，形成位移量数组dispPos
                dispPos.length=0;
                for(var k = 0; k < Attributedict['nnode']; k++){
                    dispPos.push(jsondata.results.fieldsData['Displacement_U1'][0][k]);
                    dispPos.push(jsondata.results.fieldsData['Displacement_U2'][0][k]);
                    dispPos.push(jsondata.results.fieldsData['Displacement_U3'][0][k]);
                }
                // console.log('initial dispPos:');
                // console.log(dispPos);
        }
        for (let j=0;j<resFieldInfo[i].displayName.length;j++){
            const element = resFieldInfo[i].internalName+"_"+resFieldInfo[i].displayName[j];
            menuList.value.push({ label: element, value: element});

        }

    }
}
// ------------------------
async function resFieldDisplay(resfile,fieldName){//加载结果文件，形成组，
     //
    var maxValue,minValue;
    var jsondata=await loadJSON(resfile);
    var resdata=jsondata.results;
    // console.log('物理场结果：', resdata);

    // console.log(fieldName);
    var resField=resdata.fieldsData[fieldName][0]//最后一项[0]是计算步，0表示第一步，目前只有第一步结果
    // console.log(resField);
    var resFieldExtremun=resdata.fieldsExtremum[fieldName][0];//最后一项[0]是计算步，0表示第一步场的最值，目前只有第一步结果
    // console.log(resFieldExtremun);
    colorbarConfig.Legend = fieldName;
    minValue=resFieldExtremun[1];
    if (resFieldExtremun[0]-resFieldExtremun[1]<1.0e-6){
      maxValue=minValue+1.0;
    }
    else{
      maxValue=resFieldExtremun[0];      
    }
    colorbarConfig.max=maxValue;
    colorbarConfig.min=minValue;
    
    // console.log(colorbarConfig.max);
    // console.log(colorbarConfig.min);
    lut.setMin(colorbarConfig.min);
    lut.setMax(colorbarConfig.max);
    
    var color = new THREE.Color();
  
    for ( var i = 0; i < resField.length; i ++ ) {
  
    	  var colorValue = resField[ i ];
        // console.log('Field value:',colorValue)
    	  color.copy( lut.getColor( colorValue ) ).convertSRGBToLinear();
        // console.log('corresponding color value:',color)
        Attributedict.colorsarray[3*i]=color.r;
        Attributedict.colorsarray[3*i+1]=color.g;
        Attributedict.colorsarray[3*i+2]=color.b;
    }
    updateColorBar();
    
    group.traverse((child) => {
        if (child.isGroup || child.name=='wireframe') {
            console.log("group or wireframe");   
 
        }
        else{
          // console.log(child.name);
          // console.log(child.geometry.attributes.color.count);
          CM.meshColorUpdate(child,Attributedict.colorsarray)
         }
            
    });
    // DM.Oridata2groupmesh(Attributedict,group);//根据数据对象体Attributedict绘制渲染mesh，并形成group
    // CM.BoxParaCreate(Attributedict.pointsarray,BoxPara);
    // CM.camerazoommid(camera,BoxPara);
    CM.vertexColorTrue(group);
    canvas.removeEventListener("click", onMouseClick);//点击事件移除
    //console.log(Attributedict.colorsarray)
    renderScene();

}
// 读取JSON文件
async function loadJSON(jsonfile) {//通过异步fetch加载json文件，并转成对象体返回
    const jsonfilecontent=await fetch(jsonfile);//提取jsonfile文件
    return jsonfilecontent.json();
}
// 触发文件选择器
const triggerFileSelect = () => {
  // 重置状态
  errorMessage.value = '';
  // 触发文件选择对话框
  fileInput.value.click();
};
// 处理选中的文件
const LoadGeometry = (e) => {
  // console.log('LoadGeometry');
  const file = e.target.files[0].name;
  console.log(file);
  if (!file) return;

  const mainObject = new THREE.Object3D ();
  CM.removeModel(scene);
  LoadGeometryFile (mainObject,file)
  scene.add (mainObject);
  console.log(mainObject);
  // geofileload(scene,file);
  renderScene();

};
function onMouseClick(event) { //基于射线法，实现鼠标点选几何对象
     //屏幕坐标转标准设备坐标
    mouse.x = (event.offsetX / canvas.clientWidth) * 2 - 1; //标准设备坐标x
    mouse.y = -(event.offsetY / canvas.clientHeight) * 2 + 1; //标准设备坐标y
     // 通过鼠标位置和相机信息更新射线投射器
    raycaster.setFromCamera(mouse, camera);
     // 检测射线与group相交情况
    const intersects = raycaster.intersectObjects(group.children,true);

    if ( intersects.length > 0 ) {
        // para['']=;
        // --------------------现高亮方式按照修改材料颜色统一进行----------
        if ( INTERSECTED != intersects[ 0 ].object ) {
            if ( INTERSECTED ) INTERSECTED.material.color.setHex( INTERSECTED.currentHex );
            INTERSECTED = intersects[ 0 ].object;
            INTERSECTED.currentHex=INTERSECTED.material.color.getHex();
            INTERSECTED.material.color.set( 0xff0000 );
        }
        // --------------------现高亮方式按照修改材料颜色统一进行----------
        geoObj.value =  INTERSECTED.name;
    } else {
         
        if ( INTERSECTED ) { 
           INTERSECTED.material.color.setHex( INTERSECTED.currentHex );
           //---------                   
        //    if(INTERSECTED.type=='Mesh') INTERSECTED.material.emissive.setHex( INTERSECTED.currentHex );
        //    if(INTERSECTED.type=="LineSegments") INTERSECTED.material.color.set( INTERSECTED.currentHex );
           //----------
         }
         INTERSECTED = null;
         geoObj.value =  '';
    }
    
    // return GeoName;                
}
async function LoadGeometryFile (group){
	// 使用包导入方式，避免生产环境全局变量缺失
	const occt = await getOcct();

  let result;
	// 安全校验：若 geoFileUrl 为空直接返回
  if (!geoFileUrl) {
    console.warn('[ThreeScene] geoFileUrl 为空，无法加载几何')
    return
  }
	let fileresponse;
  try {
    fileresponse = await fetch(geoFileUrl)
  } catch (err) {
    console.error('[ThreeScene] 几何文件请求失败:', err)
    return
  }
	let databuffer = await fileresponse.arrayBuffer();
	// read the imported iges or step file
	let geofileBuffer = new Uint8Array (databuffer);
  const ext = CM.getExtension(geoFileUrl).toLowerCase();
  if (ext === 'igs' || ext === 'iges') {
    result = occt.ReadIgesFile (geofileBuffer, null);
  } else if (ext === 'stp' || ext === 'step') {
    result = occt.ReadStepFile (geofileBuffer, null);
  } else {
    console.warn('[ThreeScene] 不支持的几何文件扩展名:', ext)
    return
  }
	// process the geometries of the result
	// const group = new THREE.Group();
  console.log(result);
	for (let resultMesh of result.meshes) {
		const { mesh, edges } = BuildMesh(resultMesh, true);
        group.add(mesh);
		if (edges) {
			  group.add(edges);
        }
	}
  console.log('group.children:',group.children);
	// targetObject.add(group);
  // return group;
}
function BuildMesh (geometryMesh, showEdges){
    let geometry = new THREE.BufferGeometry();
    geometry.setAttribute("position", new THREE.Float32BufferAttribute(geometryMesh.attributes.position.array, 3));
    if (geometryMesh.attributes.normal) {
        geometry.setAttribute("normal", new THREE.Float32BufferAttribute(geometryMesh.attributes.normal.array, 3));
    }
    geometry.name = geometryMesh.name;
    const index = Uint32Array.from(geometryMesh.index.array);
    console.log('geometryMesh.brep_faces:',geometryMesh.brep_faces);
    console.log('geometryMesh.color:',geometryMesh.color);
    // console.log(index);
    geometry.setIndex(new THREE.BufferAttribute(index, 1));
    const outlineMaterial = new THREE.LineBasicMaterial({ color: 0x000000 });
    const defaultMaterial = new THREE.MeshBasicMaterial({
        color: geometryMesh.color ? new THREE.Color(geometryMesh.color[0], geometryMesh.color[1], geometryMesh.color[2]) : 0xcccccc,
		side: THREE.DoubleSide,
    });
    let materials = [defaultMaterial];
    const edges = showEdges ? new THREE.Group() : null;
    if (geometryMesh.brep_faces && geometryMesh.brep_faces.length > 0) {
        var indexCount = 0;
        for (let faceColor of geometryMesh.brep_faces) {
            const color = faceColor.color ? new THREE.Color(faceColor.color[0], faceColor.color[1], faceColor.color[2]) : defaultMaterial.color;
            // const color =new THREE.Color(0.0, 0.0, indexCount/geometryMesh.brep_faces.length);
            materials.push(new THREE.MeshBasicMaterial({ color: color, side: THREE.DoubleSide, }));
            indexCount++;
        }
        const triangleCount = geometryMesh.index.array.length / 3;
        let triangleIndex = 0;
        let faceColorGroupIndex = 0;
        while (triangleIndex < triangleCount) {
            const firstIndex = triangleIndex;
            let lastIndex = null;
            let materialIndex = null;
            if (faceColorGroupIndex >= geometryMesh.brep_faces.length) {
                lastIndex = triangleCount;
                materialIndex = 0;
            } else if (triangleIndex < geometryMesh.brep_faces[faceColorGroupIndex].first) {
                lastIndex = geometryMesh.brep_faces[faceColorGroupIndex].first;
                materialIndex = 0;
            } else {
                lastIndex = geometryMesh.brep_faces[faceColorGroupIndex].last + 1;
                materialIndex = faceColorGroupIndex + 1;
                faceColorGroupIndex++;
            }
            geometry.addGroup(firstIndex * 3, (lastIndex - firstIndex) * 3, materialIndex);
            triangleIndex = lastIndex;
            // console.log('triangleIndex:',triangleIndex);
            if (edges) {
                const innerGeometry = new THREE.BufferGeometry();
                innerGeometry.setAttribute("position", geometry.attributes.position);
                if (geometryMesh.attributes.normal) {
                    innerGeometry.setAttribute("normal", geometry.attributes.normal);
                }
                // console.log('innerGeometry:');
                // console.log(index);
                innerGeometry.setIndex(new THREE.BufferAttribute(index.slice(firstIndex * 3, lastIndex * 3), 1));
                const innerEdgesGeometry = new THREE.EdgesGeometry(innerGeometry,180.0);//innerGeometry还是面片，通过THREE.EdgesGeometry提取边界
                const edge = new THREE.LineSegments(innerEdgesGeometry, outlineMaterial);
                edges.add(edge);
            }
        }
    }
    const mesh = new THREE.Mesh(geometry, materials.length > 1 ? materials : materials[0]);
    mesh.name = geometryMesh.name;
    if (edges) {
        edges.renderOrder = mesh.renderOrder + 1;
    }
    return { mesh, geometry, edges };
}
//---坐标轴初始化---
function initCoordinateSystem() {
    coordScene = new THREE.Scene();
    //coordScene.background = new THREE.Color(backgroundColor);//采用和主场景同样的背景色
    // coordScene.background = new THREE.Color(0x000000);//采用和主场景同样的背景色
    coordScene.background = null;//采用和主场景同样的背景色
    // 坐标系相机 (正交相机适合2D展示)
    coordCamera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0.1, 10);
    coordCamera.position.z = 5;
    coordCamera.lookAt(0, 0, 0);
    // coordCamera.lookAt(coordScene.position);
    //
    coordinateConfig = {
       position: { x:0, y: 0},
       sizeScale: 0.2,
    }

    coordinateSystem = createCoordinate();
    coordinateSystem.position.set(coordinateConfig.position.x, coordinateConfig.position.y, 0);
    coordScene.add(coordinateSystem);
}
function createCoordinate(){
      // 绘制坐标轴
    const coordinateGroup = new THREE.Group();
    
    const axisLength = 0.8;
    const colorred = 'red'; 
    const colorgreen = 'green'
    const colorblue = 'blue' ;
    const origin = new THREE.Vector3( 0, 0, 0 );
    const Xdir = new THREE.Vector3( 1, 0, 0 );
    const Ydir = new THREE.Vector3( 0, 1, 0 );
    const Zdir = new THREE.Vector3( 0, 0, -1 );
    //normalize the direction vector (convert to vector of length 1)
    Xdir.normalize();
    Ydir.normalize();
    Zdir.normalize();
    // 轴
    const axes_x = new THREE.ArrowHelper( Xdir, origin, axisLength, colorred );
    const axes_y = new THREE.ArrowHelper( Ydir, origin, axisLength, colorgreen );
    const axes_z = new THREE.ArrowHelper( Zdir, origin, axisLength, colorblue );
    coordinateGroup.add(axes_x);
    coordinateGroup.add(axes_y);
    coordinateGroup.add(axes_z);
    // 添加标签
    const xLabel = makeTextSprite('X', '#ff0000', 16,0.01);
    xLabel.position.set(axisLength + 0.1, 0, 0);
    coordinateGroup.add(xLabel);
    const yLabel = makeTextSprite('Y', '#00ff00', 16,0.01);
    yLabel.position.set(0, axisLength + 0.1, 0);
    coordinateGroup.add(yLabel);
    const zLabel = makeTextSprite('Z', '#0000ff', 16,0.01);
    zLabel.position.set(0, 0, -axisLength - 0.1);
    coordinateGroup.add(zLabel);
    return coordinateGroup;
}
function initColorBar() {

    // 颜色条参数
    colorbarConfig = {
        width: 60,        // 颜色条宽度（像素）
        height: 600,      // 颜色条高度（像素）
        min: 0,           // 最小值
        max: 100,         // 最大值
        steps: 6,         // 刻度数量
        position: { x: window.innerWidth - 350, y: window.innerHeight / 2 }, // 屏幕右侧居中
        Legend: 'Color Legend'
    };
    
    colorBarScene = new THREE.Scene();
    // colorBarScene.background = new THREE.Color(0, 0, 0, 0); // 完全透明背景
    colorBarScene.background = null
    // colorBarScene.background = new THREE.Color(backgroundColor);
    // colorBarScene.background = new THREE.Color(0x000000);
    // 正交相机（确保2D平面显示，无透视）
    // colorBarCamera = new THREE.OrthographicCamera(
    //     window.innerWidth / -2,  // left
    //     window.innerWidth / 2,   // right 
    //     window.innerHeight / 2,  // top
    //     window.innerHeight / -2, // bottom
    //     0.1, 1000                // near, far
    // );
    // 正交相机（确保2D平面显示，无透视）
    colorBarCamera = new THREE.OrthographicCamera(
        colorbarConfig.width / -2-30,  // left
        colorbarConfig.width / 2+60,   // right 
        colorbarConfig.height / 2+50,  // top
        colorbarConfig.height / -2-20, // bottom
        0.1, 100                // near, far
    );
    // const colorBarCamera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 1, 2 );
    // colorBarCamera.position.set( 0.5, 0, 1 );
    colorBarCamera.position.z = 100; // 沿Z轴远离平面
    // colorBarCamera.lookAt(colorBarScene.position);
    // colorBarCamera.lookAt(0,0,0);

    // 生成颜色渐变（使用Lut）
    lut = new Lut();
    lut.setMin(colorbarConfig.min);
    lut.setMax(colorbarConfig.max);

    colorBar = create2DColorBar();
    // console.log(colorBar);
    colorBarScene.add(colorBar);
    colorBar.visible = false;//false隐藏该子对象，true显示该子对象
    // console.log(colorBar.visible);
}
function updateColorBar() {
     // 清除旧的颜色条
      if (colorBar) {
          // colorbarSystem.scene.remove(colorBar);
          colorBarScene.remove(colorBar);
      }
      colorBar = create2DColorBar();
      colorBarScene.add(colorBar);
      colorBar.visible = false;//false隐藏该子对象，true显示该子对象
}
// 网格线框显隐切换
function toggleWireframeVisible(){
    // 
    group.traverse((child) => {
        if (child.isMesh && child.name=='meshFrame') {
            // 
            child.visible = !child.visible;

        }
    });
    //  renderScene();
}
// 节点显隐切换
function toggleNodesVisible(){
    //
    group.traverse((child) => {
        if (child.isPoints && child.name=='Nodes') {
            //
            child.visible = !child.visible;

        }
    });   
    //  renderScene();
}
// 变形切换
function toggleDeformation(){

    canvas.removeEventListener("click", onMouseClick);//点击事件移除

    if (activeDeformRatio==0.0) {
        activeDeformRatio=deformRatio.value;
    }
    else{
        activeDeformRatio=0.0;
    }
    group.traverse((child) => {
        if (!child.isGroup) {
            CM.meshmorph(child,iniPos,dispPos,activeDeformRatio);   
        }    
    });
    renderScene();
}
//--------------------------框选相关事件----------------------------
const mousedownfunc = (e) => {// 鼠标按下（右键启动框选）
    if (e.button !== 2) return; // 仅响应右键
    boxState.isSelecting = true;
    boxState.startX = e.clientX;
    boxState.startY = e.clientY;
    // 初始化框选位置
    boxState.boxLeft = e.clientX;
    boxState.boxTop = e.clientY;
    boxState.boxWidth = 0;
    boxState.boxHeight = 0;
    // 重置之前的选中状态
    resetSelection();
}
const mousemovefunc = (e) => {// 鼠标移动（更新框选区域）
    if (!boxState.isSelecting) return;

    const currentX = e.clientX;
    const currentY = e.clientY;
    // 计算框选矩形位置和大小
    boxState.boxLeft = Math.min(boxState.startX, currentX);
    boxState.boxTop = Math.min(boxState.startY, currentY);
    boxState.boxWidth = Math.abs(currentX - boxState.startX);
    boxState.boxHeight = Math.abs(currentY - boxState.startY);
}
const mouseupfunc = (e) => {// 鼠标释放（检测选中点）
    if (!boxState.isSelecting || e.button !== 2) return;
    boxState.isSelecting = false;
    // 框选区域坐标
    const rect = {
      x1: boxState.boxLeft,
      y1: boxState.boxTop,
      x2: boxState.boxLeft + boxState.boxWidth,
      y2: boxState.boxTop + boxState.boxHeight
    };
    // 检测框选范围内的点
    selectInRect(rect);
    console.log('框选结果:', boxState.selectedObjs);
    const selectedObjsRes = {"objType":selectedObjType,"result":boxState.selectedObjs};
    eventBus.emit('selectionEventsResult', selectedObjsRes);
}
// 框选相关事件
function SelectionEvents(objType) {

  resetSelection();
  originalColorObj = null;
  controls.enablePan = false; // 屏蔽右键平移
  selectedObjType = objType;
  if (selectedObjType=='Body') {
    selectedObj = "Mesh";
  }
  else{
    selectedObj = selectedObjType;
  }
  // console.log(selectedObj);
  // console.log(selectedObjType);
  renderContainer.value.addEventListener('mousedown', mousedownfunc);
  renderContainer.value.addEventListener('mousemove', mousemovefunc);
  renderContainer.value.addEventListener('mouseup', mouseupfunc);
}
function SelectionEventsStop(objType){
  // 仅当当前类型匹配才停止（或无条件停止也可）
  renderContainer.value.removeEventListener('mousedown', mousedownfunc);
  renderContainer.value.removeEventListener('mousemove', mousemovefunc);
  renderContainer.value.removeEventListener('mouseup', mouseupfunc);
  controls.enablePan = true; // 恢复右键平移
  
  resetSelection();
  originalColorObj = null;
  // console.log('[ThreeScene] 已停止框选:', objType);
}
// 重置选中状态（恢复蓝色）
function resetSelection() {
  // console.log('重置选中状态');
  group.traverse((child) => {
      // console.log("the type of child is:",child.type);//Group,Points,LineSegments,Mesh
      if (child.type === selectedObj) {
          // console.log("the selected type of child is:");
          // console.log(child.type);
          // console.log(child.name);
          // const colorAttr = child.geometry.attributes.color;
          // for (const i of boxState.selectedObjs) {
          //      colorAttr.setXYZ(i, 0, 0, 1); // 恢复蓝色
          // }
          // colorAttr.needsUpdate = true;
          resetSelectedObjFunc[selectedObj](child);
          boxState.selectedObjs = [];
      }
      
  }); 
  // renderScene(); 

}
function resetPointsSelection(meshmodel) {
  // console.log('重置点选中状态');
  const colorAttr = meshmodel.geometry.attributes.color;
  for (const i of boxState.selectedObjs) {
       colorAttr.setXYZ(i, 0, 0, 1); // 恢复蓝色
  }
  colorAttr.needsUpdate = true; 
}
function resetLinesSelection(meshmodel) {
  if(originalColorObj) meshmodel.material.color.setHex(originalColorObj.getHex());

  // meshmodel.material.color.setHex(originalColor.getHex());
  
  // originalColor = null;
}
function resetFacesSelection(meshmodel) {
  console.log('child meshmodel.name:',meshmodel.name);
  if(meshmodel.name == 'meshFrame'){
    return;
  }
  if(originalColorObj) {
    console.log('child model:',meshmodel.name);
    console.log('originalColor in resetFacesSelection:',originalColorObj.getHex());
    meshmodel.material.color.setHex(originalColorObj.getHex());
    // meshmodel.material.color.needsUpdate = true;
    // console.log('model name:',meshmodel.name);
    // console.log('model reset originalColor:',meshmodel.material.color.getHex());
    // console.log('model material.vertexColors:',meshmodel.material.vertexColors);
  }
  if(originalColorObj==null) return;
  
  // meshmodel.material.color.setHex(originalColor.getHex());

  originalColorObj = null;
}
// 检测框选范围内的点
function selectInRect(rect) {
  // console.log('检测框选范围内的几何体');
  let selectedObjDimension = 2;
  if (selectedObj=='Mesh') {// 如果要处理的几何体是Mesh，需要按照“Mesh”2维或“Body”3维分别处理，由几何体的名称判断
     selectedObjDimension = (selectedObjType == "Mesh" ? 2:3);
  }
  group.traverse((child) => {
      if (child.type === selectedObj && child.name!='meshFrame') {// 仅处理选中类型的几何体
          // 
          if (selectedObj=='Mesh'){
            // console.log(child.name);
            // console.log(child.name.match(/GeoE(\d)/)[1]);//提取几何对象维度
            if (parseInt(child.name.match(/GeoE(\d)/)[1]) == selectedObjDimension) {
              selectedObjFunc[selectedObj](child,rect,camera);
              child.visible = true;
            }
            else child.visible = false;
            
          } 
          // console.log(child.material.color);
          // console.log(typeof child.material.color);
          // console.log(child.material.color.getHex());
          else{
            selectedObjFunc[selectedObj](child,rect,camera);
          }
          
      }
  });  
  // const matrixWorld = points.matrixWorld; // 点集的世界矩阵

  renderScene();
}
function selectPointsInRect(points,rect,camera){
 
  const positionArray = points.geometry.attributes.position;
  const colorAttr = points.geometry.attributes.color;
  const pointsCount = points.geometry.attributes.position.count;
  const matrixWorld = points.matrixWorld;// 点集的世界矩阵
  // 遍历所有点
  for (let i = 0; i < pointsCount; i++) {
    // 获取点的本地坐标
    const x = positionArray.getX(i);
    const y = positionArray.getY(i);
    const z = positionArray.getZ(i);

    // 转换为世界坐标
    const worldPos = new THREE.Vector3(x, y, z).applyMatrix4(matrixWorld);

    // 转换为屏幕坐标
    const screenPos = worldPos.project(camera);
    const screenX = (screenPos.x * 0.5 + 0.5) * renderContainer.value.clientWidth;
    const screenY = (-screenPos.y * 0.5 + 0.5) * renderContainer.value.clientHeight;

    // 判断是否在框选范围内
    if (screenX >= rect.x1 && screenX <= rect.x2 && screenY >= rect.y1 && screenY <= rect.y2) {
      boxState.selectedObjs.push(i);
      // 标记为红色
      // colorAttr.setXYZ(i, 1, 0, 0);
    }
  }
  // colorAttr.needsUpdate = true; // 通知渲染器颜色已更新
  highlightSelectedPoints(boxState.selectedObjs);
}
function highlightSelectedPoints(pointsIndexArray){
  const points=group.children.find((child) => child.name === 'Nodes');
  // console.log('pointsIndexArray:',pointsIndexArray);
  // console.log('points:',points);
  const colorAttr = points.geometry.attributes.color;
  for (const i of pointsIndexArray) {
       colorAttr.setXYZ(Number(i), 1, 0, 0); // 红色
  }
  colorAttr.needsUpdate = true; 
}
function highlightOffSelectedPoints(pointslist){
  const points=group.children.find((child) => child.name === 'Nodes');
  // console.log('highlightOffSelectedPoints',pointsIndexArray);
  // console.log('pointslist',pointslist);
  // console.log('points:',points);
  const colorAttr = points.geometry.attributes.color;
  pointslist.forEach((item) => {

  colorAttr.setXYZ(Number(item), 0, 0, 1); // 蓝色
 })
 colorAttr.needsUpdate = true;
}

// function confirmSelect(){
//   // console.log('确认框选');
//   console.log(boxState.selectedObjs);
//   resetSelection();
//   renderScene();
//   controls.enablePan = true; // 屏蔽右键平移
//   renderContainer.value.removeEventListener('mousedown', mousedownfunc);
//   renderContainer.value.removeEventListener('mousemove', mousemovefunc);
//   renderContainer.value.removeEventListener('mouseup', mouseupfunc);
//   originalColorObj = null;
// } 
//核心函数：检测框选范围内的线段
function selectLinesInRect(lines,rect,camera) {
  originalColorObj = lines.material.color.clone();
  const positionAttr = lines.geometry.attributes.position;
  const indexAttr = lines.geometry.index;
  const matrixWorld = lines.matrixWorld; // 线集的世界矩阵
  const selectedLineIndices = [];
  //
  const rectEdges = [
        { type: 'left', x: rect.x1, y1: rect.y1, y2: rect.y2 },   // 左边
        { type: 'right', x: rect.x2, y1: rect.y1, y2: rect.y2 },  // 右边
        { type: 'top', y: rect.y1, x1: rect.x1, x2: rect.x2 },    // 上边
        { type: 'bottom', y: rect.y2, x1: rect.x1, x2: rect.x2 }  // 下边
  ];
  for (let i = 0; i < lines.geometry.index.count; i+=2) {
        const idx0 = indexAttr.getX(i);
        const idx1 = indexAttr.getX(i + 1);
        // 获取面的2个顶点（屏幕坐标）
        const p0 = getScreenPos(idx0, positionAttr, matrixWorld, camera);
        const p1 = getScreenPos(idx1, positionAttr, matrixWorld, camera);
        // 条件1：任意顶点在框内 → 选中
        const isP0In = isPointInRect(p0, rect);
        const isP1In = isPointInRect(p1, rect);
        if(isP0In || isP1In){
          selectedLineIndices.push(i);
          continue;
        }
        // 条件2：线段与矩形边相交 → 选中
        if (isLineIntersectRect(p0, p1, rectEdges)) {
          selectedLineIndices.push(i);
        }
  }
  // 更新选中线段的颜色（通过材质实例化实现）
  if(selectedLineIndices.length > 0){
    lines.material.color.setHex(selectedColor);
    boxState.selectedObjs.push(lines.name);
  }
  else{
    lines.material.color.setHex(originalColorObj.getHex()); 
    // originalColorObj = null;
  }
} 
//辅助函数：判断线段与矩形边是否相交
function isLineIntersectRect(p1, p2, rectEdges) {
    for (const edge of rectEdges) {
        if (isLineIntersect(p1, p2, edge)) {
            return true;
        }
    }
    return false;
}
//辅助函数：判断线段与单条矩形边是否相交
function isLineIntersect(p1, p2, edge) {
    // 线段：p1 -> p2
    // 矩形边：水平或垂直直线
    const dx = p2.x - p1.x;
    const dy = p2.y - p1.y;
    if (edge.type === 'left' || edge.type === 'right') {
        // 垂直边（x = edge.x）
        const x = edge.x;
        if (dx === 0) return false; // 线段平行，不相交
        const t = (x - p1.x) / dx; // 相交参数（0~1 表示在线段上）
        if (t < 0 || t > 1) return false;
        const y = p1.y + t * dy; // 相交点y坐标
        // 判断y是否在边的y范围内
        return y >= Math.min(edge.y1, edge.y2) && y <= Math.max(edge.y1, edge.y2);
    } else {
        // 水平边（y = edge.y）
        const y = edge.y;
        if (dy === 0) return false; // 线段水平，不相交
        const t = (y - p1.y) / dy; // 相交参数
        if (t < 0 || t > 1) return false;
        const x = p1.x + t * dx; // 相交点x坐标
        // 判断x是否在边的x范围内
        return x >= Math.min(edge.x1, edge.x2) && x <= Math.max(edge.x1, edge.x2);
    }
}
// 核心函数：检测面是否与框选区域相交
function selectFacesInRect(mesh,rect,camera) {
    const geometry = mesh.geometry;

    const indexAttr = geometry.index;
    const positionAttr = geometry.attributes.position;
    const matrixWorld = mesh.matrixWorld;
    const selectedLineIndices = [];
    //
    if(mesh.name == 'meshFrame'){
      return;
    }
    if(!originalColorObj) {
      
      originalColorObj = mesh.material.color.clone();
      console.log('only clone the first time:',originalColorObj.getHex());
    }
    else {
      console.log('not clone the first time:',originalColorObj.getHex());
    }

    // console.log('selectFaces originalColor:',originalColorObj.getHex());
    // console.log('selectFacesIn mesh lColor:',mesh.material.color);
    // console.log('selectFacesInRect originalColor:',originalColor);
    // console.log('selectFaces mate:',mate);
    // console.log('selectFaces mate:',mate.color);
    const rectEdges = [// 框的4条边
          { type: 'left', x: rect.x1, y1: rect.y1, y2: rect.y2 },   // 左边
          { type: 'right', x: rect.x2, y1: rect.y1, y2: rect.y2 },  // 右边
          { type: 'top', y: rect.y1, x1: rect.x1, x2: rect.x2 },    // 上边
          { type: 'bottom', y: rect.y2, x1: rect.x1, x2: rect.x2 }  // 下边
    ];
    // 遍历所有面（每个面3个顶点）
    for (let i = 0; i < indexAttr.count; i += 3) {
        const idx0 = indexAttr.getX(i);
        const idx1 = indexAttr.getX(i + 1);
        const idx2 = indexAttr.getX(i + 2);
        // 获取面的3个顶点（屏幕坐标）
        const p0 = getScreenPos(idx0, positionAttr, matrixWorld,camera);
        const p1 = getScreenPos(idx1, positionAttr, matrixWorld,camera);
        const p2 = getScreenPos(idx2, positionAttr, matrixWorld,camera);
        // 条件1：任意顶点在框内 → 选中
        const isP0In = isPointInRect(p0, rect);
        const isP1In = isPointInRect(p1, rect);
        const isP2In = isPointInRect(p2, rect);
        if (isP0In || isP1In || isP2In) {
            selectedLineIndices.push(i);
            continue;
        }
        // 条件2：面的任意边与框的任意边相交 → 选中
        const edges = [
            { a: p0, b: p1 }, // 面的边1
            { a: p1, b: p2 }, // 面的边2
            { a: p2, b: p0 }  // 面的边3
        ];
        let isIntersect = false;
        for (const edge of edges) {
            if (isLineIntersectRect(edge.a, edge.b, rectEdges)) {
                isIntersect = true;
                break;
            }
            if (isIntersect) break;
        }
        if (isIntersect) {
            selectedLineIndices.push(i);
            continue;
        }
        // 条件3：框完全被面包围 → 选中（可选，提高精度）
        if (isRectInsideFace(rect, [p0, p1, p2])) {
            selectedLineIndices.push(i);
        }
    }
    // geometry.attributes.color.needsUpdate = true;
  // 更新选中面的颜色（通过材质实例化实现）
  if(selectedLineIndices.length > 0){
    mesh.material.color.setHex(selectedColor);
    boxState.selectedObjs.push(mesh.name);
  }
  else{
    mesh.material.color.setHex(originalColorObj.getHex());
    originalColorObj = null;
  }
  // console.log('after selectFaces done:',originalColorObj.getHex());
}
// 辅助函数：判断点是否在矩形内
function isPointInRect(point, rect) {
    return (
        point.x >= rect.x1 && point.x <= rect.x2 &&
        point.y >= rect.y1 && point.y <= rect.y2
    );
}
// 辅助函数：获取顶点的屏幕坐标
function getScreenPos(vertexIndex, positionAttr, matrixWorld,camera) {
    const p = new THREE.Vector3(
        positionAttr.getX(vertexIndex),
        positionAttr.getY(vertexIndex),
        positionAttr.getZ(vertexIndex)
    ).applyMatrix4(matrixWorld).project(camera);
    return {
        x: (p.x * 0.5 + 0.5) * window.innerWidth,
        y: (-p.y * 0.5 + 0.5) * window.innerHeight
    };
}
// 辅助函数：判断矩形是否完全在面的投影内（可选）
function isRectInsideFace(rect, facePoints) {
    // 取矩形的4个顶点
    const rectPoints = [
        { x: rect.x1, y: rect.y1 },
        { x: rect.x2, y: rect.y1 },
        { x: rect.x2, y: rect.y2 },
        { x: rect.x1, y: rect.y2 }
    ];
    // 若矩形所有顶点都在面内，则判定为包含
    return rectPoints.every(p => isPointInTriangle(p, facePoints[0], facePoints[1], facePoints[2]));
}
// 辅助函数：判断点是否在三角形内（ barycentric 重心坐标法）
function isPointInTriangle(p, a, b, c) {
    const v0 = { x: c.x - a.x, y: c.y - a.y };
    const v1 = { x: b.x - a.x, y: b.y - a.y };
    const v2 = { x: p.x - a.x, y: p.y - a.y };
    // 计算向量点积
    const dot00 = v0.x * v0.x + v0.y * v0.y;
    const dot01 = v0.x * v1.x + v0.y * v1.y;
    const dot02 = v0.x * v2.x + v0.y * v2.y;
    const dot11 = v1.x * v1.x + v1.y * v1.y;
    const dot12 = v1.x * v2.x + v1.y * v2.y;
    // 计算重心坐标
    const denom = dot00 * dot11 - dot01 * dot01;
    if (denom === 0) return false; // 三角形退化
    const u = (dot11 * dot02 - dot01 * dot12) / denom;
    const v = (dot00 * dot12 - dot01 * dot02) / denom;
    // 点在三角形内（包括边缘）
    return (u >= 0) && (v >= 0) && (u + v <= 1);
}
//--------------------------***************----------------------------
// ----------------------主题相关动态变量---------------
const isDarkTheme = ref(false);
let tickColor = '#333333'; // 颜色条刻度与标签颜色
let themeObserver; // MutationObserver 引用
function detectTheme() {
  // 使用 html.dark 类判断
  return document.documentElement.classList.contains('dark');
}
function applyTheme() {
  isDarkTheme.value = detectTheme();
  backgroundColor = isDarkTheme.value ? 0x141414 : 0xffffff;
  // 更新主场景背景
  if (scene) scene.background = new THREE.Color(backgroundColor);
  // 更新坐标轴场景背景
  if (coordinateSystem?.scene) coordinateSystem.scene.background = new THREE.Color(backgroundColor);
  // 刻度与文字颜色
  tickColor = isDarkTheme.value ? '#d0d0d0' : '#333333';
  // 重建颜色条以应用新刻度颜色
  if (colorBarScene && colorBar) {
    updateColorBar();
  }
  // 重新渲染
  renderScene();
}
function startThemeObserver() {
  themeObserver = new MutationObserver(() => applyTheme());
  themeObserver.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] });
}

// 修改 createTextSprite 使用动态 tickColor
// 坐标轴标签
const makeTextSprite = (text, color, size,scale) => {//字体用
    const canvas = document.createElement('canvas');
    const context = canvas.getContext('2d');
    context.font = `${size}px Arial`;
    
    // 测量文本宽度
    const metrics = context.measureText(text);
    const textWidth = metrics.width;
    canvas.width = textWidth;
    canvas.height = size * 1.5;
    
    // 重设字体，因为画布尺寸变了
    context.font = `${size}px Arial`;
    context.fillStyle = color;
    context.fillText(text, 0, size);
    const texture = new THREE.CanvasTexture(canvas);
    const sprite = new THREE.Sprite(new THREE.SpriteMaterial({ map: texture }));
    sprite.scale.set(textWidth*scale, size*scale*2.0, 1);
    return sprite;
};
// 用于颜色条刻度与标题的文本创建，改为引用 tickColor

// 修改 create2DColorBar 中 tick 与文本颜色使用 tickColor
// 创建颜色条（使用Lut和Sprite）
function create2DColorBar() {
    const colorBarGroup = new THREE.Group();
    
    const barPos = screenToCamera(colorbarConfig.position.x, colorbarConfig.position.y);
    // console.log(window.innerWidth);
    // console.log(barPos);
    // colorBarGroup.position.set(barPos.x, barPos.y, 0);
    // colorBarGroup.scale.set(1.5, 1.1, 0)
    //
    const texture = new THREE.CanvasTexture(lut.createCanvas());
    const barSprite = new THREE.Sprite(new THREE.SpriteMaterial({ map: texture }));
    //
    barSprite.scale.set(colorbarConfig.width, colorbarConfig.height, 1);
    barSprite.position.set(0, 0, 0); // 相对于组的中心
    colorBarGroup.add(barSprite);
    // 颜色条标题
    // const titleSprite = createTextSprite(colorbarConfig.Legend, 18);
    const titleSprite = makeTextSprite(colorbarConfig.Legend, tickColor,18,0.8);
    titleSprite.position.set(0, colorbarConfig.height / 2 + 20, 1); // 标题位置
    colorBarGroup.add(titleSprite);
    // 添加刻度和标签
    const step = (colorbarConfig.max - colorbarConfig.min) / (colorbarConfig.steps - 1);
    const stepHeight = colorbarConfig.height / (colorbarConfig.steps - 1);
    for (let i = 0; i < colorbarConfig.steps; i++) {
        const value = colorbarConfig.max - i * step;
        const yPos = (colorbarConfig.height / 2) - (i * stepHeight); // 从顶部开始计算
        // 刻度线
        const tick = new THREE.Sprite(new THREE.SpriteMaterial({
            color: 0x333333
        }));
        tick.scale.set(10, 1, 1); // 刻度线大小
        tick.position.set(colorbarConfig.width / 2-5, yPos, 1); // 右侧偏移
        colorBarGroup.add(tick);
        // 刻度标签
        // console.log(value,value.toExponential(2));
        // const textSprite = createTextSprite(value.toExponential(2), 14);
        const textSprite = makeTextSprite(value.toExponential(2), tickColor, 14,0.8);
        textSprite.position.set(
            colorbarConfig.width / 2 +30, 
            yPos, 
            1
        );
        colorBarGroup.add(textSprite);
    }
    return colorBarGroup;
}
// 转换屏幕坐标到正交相机坐标
const screenToCamera = (x, y) => {
        return {
            x: x - window.innerWidth / 2,
            y: y - window.innerHeight / 2
        };
};
//---------
// 处理菜单选择
const handleCommand = (command) => {
  // console.log('选中的物理场：', command);
  // 根据 command 执行对应操作（如编辑、删除）
  resFieldDisplay(resfile,command);
};
// ------------------------
// 处理窗口大小变化
const handleResize = () => {
  // console.log('窗口大小变化');
  if (!renderContainer.value) return;
  
  const width = renderContainer.value.clientWidth;
  const height = renderContainer.value.clientHeight;
  
  camera.aspect = width / height;
  camera.updateProjectionMatrix();
  renderer.setSize(width, height);
  //
  // renderScene();
};
function morphAnimateExecute(){
    const delta = clock.getDelta();
    totalTime += delta;
    // 
    frameCount = Math.floor(totalTime / frameDuration);
    // 
    if (frameCount > lastFrameCount) {
        lastFrameCount = frameCount;
        var ratio=(lastFrameCount%(totalframes+1))/totalframes;
        // 
        group.traverse((child) => {
            if (!child.isGroup) {
                CM.meshmorph(child,iniPos,dispPos,ratio*deformRatio.value);   
            }            
        });        
        // renderScene();
    }
    if(totalTime>maxDuration){totalTime=0.0;lastFrameCount=0;}
}

function stopmorphAnimate(){
        // cancelAnimationFrame(animation01);
        // animation01=null;
        if(morphFlag) return;
        group.traverse((child) => {
            if (!child.isGroup) {
                CM.meshmorph(child,iniPos,dispPos,activeDeformRatio);   
            }            
        }); 
        morphFlag=true;
        // renderScene();
}
// 切换动物变形动画
function toggleDeformationAnimal() {
    morphAnimationFlag=!morphAnimationFlag;
    if(morphAnimationFlag){
        morphFlag=true;
    }
    else{
        morphFlag=false;
    }
}
function switchView(viewType='front') {
  if (!camera || !Attributedict) return;

  // 模型中心（世界原点，因模型已居中）
  const targetCenter = new THREE.Vector3(0, 0, 0);
  // 相机距离模型的距离（基于模型尺寸，确保完全显示）
  const modelSize = CM.getModelSize(Attributedict);
  const distance = Math.max(modelSize.x, modelSize.y, modelSize.z) * 1.2; // 距离系数，可调整

  // 根据视图类型设置相机位置
  switch (viewType) {
    case 'front': // 正视图（Z+ 轴方向）
      camera.position.set(0, 0, distance);
      break;
    case 'top': // 俯视图（Y+ 轴方向）
      camera.position.set(0, distance, 0);
      break;
    case 'side': // 侧视图（左视图，X+ 轴方向）
      camera.position.set(distance, 0, 0);
      break;
    case 'back': // 后视图（Z- 轴方向）
      camera.position.set(0, 0, -distance);
      break;
    case 'bottom': // 底视图（Y- 轴方向）
      camera.position.set(0, -distance, 0);
      break;
    case 'right': // 右视图（X- 轴方向）
      camera.position.set(-distance, 0, 0);
      break;
  }

  // 相机始终朝向模型中心
  camera.lookAt(targetCenter);
  // 若使用控制器，更新控制器目标
  if (controls) controls.target.copy(targetCenter);
}
function switchInfoFeatrueVisiable(infoFeatrue) {
  //
  switch (infoFeatrue) {
    case 'toggleFrame': // 网格框显隐
      toggleWireframeVisible();
      break;
    case 'toggleNode': // 节点显隐
      toggleNodesVisible();
      break;
  }
}
//----
function switchModelFeatrueVisiable(infoFeatrue) {
  //
  switch (infoFeatrue) {
    case 'toggleGeometryModel': // 几何模型显隐
      // if(infoFeatrue.flag){
      //   scene.add(oriGeometryGroup);
      //   oriGeometryGroup.visible=true;
      // }
      // else{
      //   scene.remove(oriGeometryGroup);
      //   oriGeometryGroup.visible=false;
      // }
      oriGeometryGroup.visible=!oriGeometryGroup.visible;
      break;
    case 'toggleMeshModel': // 网格模型显隐
      // if(infoFeatrue.flag){
      //   scene.add(group);
      //   group.visible=true;
      // }
      // else{
      //   scene.remove(group);
      //   group.visible=false;
      // }
      group.visible=!group.visible;
      break;
  }
}
// ----------
function regionSetHighLight(regionSet){//高亮显示区域
  // console.log("regionSet:",regionSet);
  // console.log("regionSet type:",typeof regionSet);
  // console.log("regionSet array:",Array.from(regionSet));
  var BodyorSurface=0;
  const regionSetArrayRes=Array.from(regionSet);
  if(CM.isScientificNumber(regionSetArrayRes[0])){
    // console.log("regionSetArrayRes is points",regionSetArrayRes);
    highlightSelectedPoints(regionSet)
  }
  else{
    console.log("regionSetArrayRes is line/face/body",regionSetArrayRes);
    for (const iElement of regionSet) {
      
      const meshmodel=group.children.find((child) => child.name === iElement);
      if(!originalColorObj){
        console.log("originalColorObj is null");
        originalColorObj = meshmodel.material.color.clone(); 
        console.log("originalColorObj in regionSetArrayRes:",originalColorObj.getHex());
      }
      if(parseInt(meshmodel.name.match(/GeoE(\d)/)[1]) == 2 && !BodyorSurface)BodyorSurface=3;
      if(parseInt(meshmodel.name.match(/GeoE(\d)/)[1]) == 3 && !BodyorSurface)BodyorSurface=2;
      // console.log("geoElementDimension:",geoElementDimension);
      meshmodel.material.color.setHex(selectedColor);
    }
    
  }
  if(BodyorSurface>1){
    console.log("BodyorSurface after:",BodyorSurface);
    group.traverse((child) =>{
        if(child.isMesh && child.name!="meshFrame") {
          // console.log("child.name:",child.name);
          if (parseInt(child.name.match(/GeoE(\d)/)[1]) == BodyorSurface) child.visible = false;
        } 
    })
    }  
  return;
}
function regionSetHighLightOff(regionSet){//关闭选择区域高亮显示
  console.log("regionSetHighLightOff:",regionSet);
  const regionSetlist=regionSet.split(',');
  var BodyorSurface=0;
  // const regionSetArrayRes=Array.from(regionSet);
  if(CM.isScientificNumber(regionSet[0])){
    // console.log("regionSetHighLightOff regionSetArrayRes is points");
    highlightOffSelectedPoints(regionSetlist)
  }
  else{
    console.log("regionSetHighLightOff regionSetArrayRes is line/face/body");
    console.log(regionSetlist);
    regionSetlist.forEach((item) => {
      const itemName = item.replace(/^\s+|\s+$/g, '');
      const meshmodel=group.children.find((child) => child.name === itemName);
      if(parseInt(itemName.match(/GeoE(\d)/)[1]) == 2 && !BodyorSurface)BodyorSurface=3;
      if(parseInt(itemName.match(/GeoE(\d)/)[1]) == 3 && !BodyorSurface)BodyorSurface=2;
      meshmodel.material.color.setHex(originalColorObj);
    })
    originalColorObj=null;
    if(BodyorSurface>1){
       console.log("BodyorSurface after:",BodyorSurface);
       group.traverse((child) =>{
        if(child.isMesh && child.name!="meshFrame") {
          // console.log("child.name:",child.name);
          if (parseInt(child.name.match(/GeoE(\d)/)[1]) == BodyorSurface) child.visible = true;
        } 
    })
    }  
  }
}
// ----------剖面相关操作-------------------
function clippingEvents(clippingFeature){
  // console.log("clippingEvents in threescene:",clippingFeature);
  clippingPlaneInit();
  const PlaneTag=clippingFeature.PlaneTag;
  const flag=clippingFeature.flag;
  const sign = flag ? 1 : -1;
  if (PlaneTag == "cancle") {
    console.log("cancel clipping");
    renderer.clippingPlanes = [];
    return;
  }
  // // console.log(offsetDistance.value);
  // // console.log(clippingPlane[clippingPlaneTag[PlaneTag]]);
  clippingPlane[clippingPlaneTag[PlaneTag]].constant = 0.0;
  clippingPlane[clippingPlaneTag[PlaneTag]].normal = clippingPlaneVectorRef[PlaneTag].clone().multiplyScalar(sign);
  renderer.clippingPlanes = [clippingPlane[clippingPlaneTag[PlaneTag]]];
}
function handleClippingOffsetChange(offsetfeatrue){
  const indexmap = {'YZ':"x",'ZX':"y",'XY':"z"};
  // console.log("handleClippingOffsetChange in three:",offsetfeatrue);
  const PlaneTag = offsetfeatrue.sectionViewFeature.PlaneTag;
  // console.log("handleClippingOffsetChange in three:",offsetvalue.sectionViewFeature.PlaneTag);
  const boundingBox = CM.attributedictBoundingBox(Attributedict);
  // console.log("boundingBox referrence:",boundingBox.max);
  // console.log("boundingBox referrence:",boundingBox.max[indexmap[PlaneTag]]);
  const offsetRange=boundingBox.max[indexmap[PlaneTag]];
  const offsetRatio = offsetfeatrue.offsetValue;
  const offsetvalue = offsetRange*offsetRatio;
  if (renderer.clippingPlanes.length==0) {
    return;
  }else{
    renderer.clippingPlanes[0].constant = offsetvalue;
  }
}
function clippingPlaneInit(){
  if(clippingPlane) return;
  const boundingBox = CM.attributedictBoundingBox(Attributedict);
  console.log("boundingBox:",boundingBox);
  // 计算包围盒中心
  const center = new THREE.Vector3();
  boundingBox.getCenter(center);  
  clippingPlane = [
					new THREE.Plane( clippingPlaneVectorRef['YZ'].clone(), center.x ),
					new THREE.Plane( clippingPlaneVectorRef['ZX'].clone(), center.y ),
					new THREE.Plane( clippingPlaneVectorRef['XY'].clone(), center.z )
				];
  // console.log("clippingPlane init",clippingPlane);
	const planeHelpers = clippingPlane.map( p => new THREE.PlaneHelper( p, 60, 0x000099 ) );
	planeHelpers.forEach( ph => {
					ph.visible = false;
					scene.add( ph );
				} );
}
// ----------剖面相关操作-------------------
// 动画循环渲染
const animate = () => {
  animationId=requestAnimationFrame(animate);
  // if(morphAnimationFlag){
  //   morphAnimateExecute();
  // }
  // else{
  //   stopmorphAnimate();
  // }
  controls.update();
  renderScene();
};
//渲染总控制函数
const renderScene = () => {
  // 渲染主场景
  // renderer.autoClear = false;
  renderer.setViewport(0, 0, window.innerWidth, window.innerHeight);
  renderer.render(scene, camera);

  renderer.autoClear = false;
  renderer.clearDepth();
  renderer.setScissorTest( true );
  renderer.setScissor( window.innerWidth-colorbarConfig.width*6-20, window.innerHeight/2-colorbarConfig.height/2, colorbarConfig.width*2, colorbarConfig.height );
	renderer.setViewport( window.innerWidth-colorbarConfig.width*6-20, window.innerHeight/2-colorbarConfig.height/2, colorbarConfig.width*2, colorbarConfig.height );
  // const barPos = screenToCamera(colorbarConfig.position.x, colorbarConfig.position.y);
  // colorBar.position.set(barPos.x, barPos.y, 0);
  // colorBar.scale.set(1.0);
  renderer.render(colorBarScene, colorBarCamera);
  //-------------坐标系统的渲染-----------
  renderer.setScissorTest( true );
  renderer.clearDepth(); // important!
  coorWidth=coordinateConfig.sizeScale*window.innerHeight;
  coorHeight=coordinateConfig.sizeScale*window.innerHeight;
  coordinateSystem.quaternion.copy(camera.quaternion);
	
	renderer.setScissor( 10, 50, coorWidth, coorHeight );
	renderer.setViewport( 10, 50, coorWidth, coorHeight );
  renderer.render(coordScene, coordCamera);
  renderer.autoClear = true;
  renderer.setScissorTest( false );
}
// 新增：当前几何文件的 URL（由 partChildren-file-selected 事件提供）
let geoFileUrl = '';
const handlePartChildrenSelected = ({ filePath } = {}) => {
  //debugger
  if (!filePath || geoFileUrl === filePath) return;
  geoFileUrl = filePath;
  console.log('[ThreeScene] 接收到几何文件路径:', geoFileUrl);
  tryAutoLoadGeometry();
}

const tryAutoLoadGeometry = () => {
  if (!geoFileUrl || !scene) return;
  // const mainObject = new THREE.Object3D()
  // CM.removeModel(scene);
  
  CM.clearGroup(oriGeometryGroup);
  LoadGeometryFile(oriGeometryGroup);
  oriGeometryGroup.updateMatrixWorld(true);
  scene.add(oriGeometryGroup);
  oriGeometryGroup.visible=true;
  group.visible=false;
  // const groupBox = getGroupBoundingBox(group);
  // console.log("模型包围盒:", groupBox);

  // 模型居中
  // CM.centerModel(group);
  // CM.BoxParaCreate(Attributedict.pointsarray,BoxPara);
  // CM.camerazoommid(camera,BoxPara);
  // renderScene();
}
//----
function Meshing(data) {
  // console.log('Meshing in ThreeScene:',meshdata);
  // 调用封装后的 FEM 接口
  // Django 返回的数据本身即为 data（拦截器已处理）
  const mshjsondata=data['jsonmshfile'];
  //
  mshJsonMeshing(mshjsondata);
}
function mshJsonMeshing(mshjsondata) {
  // 根据已经设定好的mshjsondata数据结构形成Attributedict，并在三维引擎绘制网格
  //
  Attributedict=CM.mshAttributesObjCreate(mshjsondata);//根据导入的网格数据对象，形成本次要渲染mesh的数据对象体Attributedict
  // console.log(Attributedict);
  iniPos=Attributedict['pointsarray'].array.slice();//初始化初始位置
  dispPos = new Array(iniPos.length).fill(0);//初始化位移量为0
  CM.clearGroup(group);
  // DM.Oridata2groupmesh(Attributedict,group);//根据数据对象体Attributedict绘制渲染mesh，并形成group
  DM.Oridata2GroupMeshObj(Attributedict,group);//根据数据对象体Attributedict绘制渲染mesh，并形成group
  // console.log(group);
  scene.add(group);
  group.visible=true;
  oriGeometryGroup.visible=false;
  CM.centerModel(group,Attributedict);//模型居中
  //
  switchView();
}
function receiveMesh(data) {

  // console.log('Meshing in ThreeScene:',data);
  Attributedict={};
  mshJsonMeshing(data.data);
}
// 生命周期钩子
onMounted(() => {
  // 提前初始化 OCCT 内核，不阻塞后续操作
  getOcct().then(() => {
    console.log('OCCT assembly kernel initialized on component mount.');
  }).catch(err => {
    console.error('OCCT kernel pre-initialization failed:', err);
  });

  // 确保容器已挂载
  if (renderContainer.value) {
    initScene();
    animate();
    applyTheme(); // 初始应用主题
    startThemeObserver(); // 监听主题切换
  }
  eventBus.on('partChildren-file-selected', handlePartChildrenSelected);//接收几何文件路径
  eventBus.on('meshEvent', Meshing);//网格剖分
  eventBus.on('existMeshEvent', receiveMesh);//接收之前所划分的网格剖分
  eventBus.on('SelectionEvents', SelectionEvents);//框选事件
  eventBus.on('SelectionEventsStop', SelectionEventsStop);//框选结束事件
  eventBus.on('regionSetResult', regionSetHighLight);//接收高亮区域
  eventBus.on('regionSetResultOff', regionSetHighLightOff);//接收高亮区域
  eventBus.on('viewFetureSelected', switchView);//接收视图功能按钮选择
  eventBus.on('infoVisibleFeatureSelected', switchInfoFeatrueVisiable);//接收信息功能按钮选择
  eventBus.on('modelVisibleFeatureSelected', switchModelFeatrueVisiable);//接收模型功能按钮选择
  eventBus.on('sectionViewFeatureSelected', clippingEvents);//接收剖面视图功能按钮选择
  eventBus.on('handleClippingOffsetChange', handleClippingOffsetChange);//接收剖面位置滑动条变化事件
});

onUnmounted(() => {
  // 清理资源
  window.removeEventListener('resize', handleResize);
  cancelAnimationFrame(animationId);
  
  
  // 清理渲染器
  if (renderContainer.value && renderer?.domElement) {
    renderContainer.value.removeChild(renderer.domElement);
  }
  renderer?.dispose();
  if (themeObserver) themeObserver.disconnect();
  eventBus.off('partChildren-file-selected', handlePartChildrenSelected);//接收几何文件路径
  eventBus.off('meshEvent', Meshing);//网格剖分
  eventBus.off('existMeshEvent', receiveMesh);//接收之前所划分的网格剖分
  eventBus.off('SelectionEvents', SelectionEvents);//框选事件
  eventBus.off('SelectionEventsStop', SelectionEventsStop);//框选结束事件
  eventBus.off('regionSetResult', regionSetHighLight);//接收高亮区域
  eventBus.off('regionSetResultOff', regionSetHighLightOff);//接收高亮区域
  eventBus.off('viewFetureSelected', switchView);//接收视图功能按钮选择
  eventBus.off('infoVisibleFeatureSelected', switchInfoFeatrueVisiable);//接收信息功能按钮选择
  eventBus.off('modelVisibleFeatureSelected', switchModelFeatrueVisiable);//接收模型功能按钮选择
  eventBus.off('sectionViewFeatureSelected', clippingEvents);//接收剖面视图功能按钮选择
  eventBus.off('handleClippingOffsetChange', handleClippingOffsetChange);//接收剖面位置滑动条变化事件
});

// 监视容器大小变化
watchEffect(() => {
  if (renderContainer.value) {
    handleResize();
  }
});


</script>

<style scoped>
.three-container {
  display: flex;
  flex-direction: column;
  height: 100vh;
  width: 100%;
}

.render-container {
  flex: 1;
  width: 100%;
  height: 100%;
}

.controls-panel {
  background-color: #2a2a40;
  color: white;
  padding: 1rem;
  display: flex;
  gap: 2rem;
  flex-wrap: wrap;
  align-items: center;
}

.control-group {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

button {
  background-color: #42b983;
  color: white;
  border: none;
  padding: 0.5rem 1rem;
  border-radius: 4px;
  cursor: pointer;
  transition: background-color 0.3s;
}

button:hover {
  background-color: #359e75;
}

input[type="range"] {
  width: 200px;
}
/* 核心：完全隐藏文件选择器 */
.file-input {
  /* 隐藏元素且不占据任何空间 */
  display: none;
  /* 额外保险：即使display失效，也通过定位和透明度隐藏 */
  position: absolute;
  opacity: 0;
  pointer-events: none; /* 禁止鼠标交互 */
}

.el-dropdown-link {
  cursor: pointer;
  color: hsl(344, 87%, 50%);
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 8px 16px;
}
.selection-box {
  position: fixed;
  border: 2px solid #ff0000;
  background: rgba(255, 0, 0, 0.1);
  pointer-events: none;
}
</style>
